# -*- coding: utf-8 -*-

"""
CMDB相关。
"""

import json
import math

# 3-party
import requests

from .log import get_logger
from .config import SERVER_IP
from .config import USER


logger = get_logger(__name__, "INFO")


class CMDBResource(object):
    """CMDB资源对象操作。"""
    
    def __init__(self, modelId, org, host=SERVER_IP, user=USER):
        self.modelId = modelId
        self.__url = "http://%s" % host
        self.__headers = {
            "org": org,
            "user": user,
            "host": "cmdb_resource.easyops-only.com",
            "content-type": "application/json",
        }
    
    @staticmethod
    def get_all(func, pageSize=500, **kwargs):
        """以分页的方式取回所有实例。
        
        参数：
        - func：查询函数；
        - pageSize：分页大小，默认500；
        - **kwargs：传递至查询函数的参数；
        """
        reses = []

        res = func(page=1, pageSize=pageSize, **kwargs)

        total = res["data"]["total"]
        pages = range(int(math.ceil(float(total) / float(pageSize))) + 1)[2:]
        
        reses.extend(res["data"]["list"])
        for i in pages:
            res = func(page=i, pageSize=pageSize, **kwargs)
            reses.extend(res["data"]["list"])
        return reses
    
    @staticmethod
    def __err_handle(resObj):
        """错误处理。
        
        参数：
        - resObj：响应对象；
        """
        resObj.raise_for_status()

        res = resObj.json()
        if res["code"] != 0:
            logger.critical(u"API请求失败：%s" % json.dumps(res))
            # TODO：丰富logger配置，使用处理器引发异常
            raise Exception("return code non-zero")
    
    def __send_request(self, method, url, data=None):
        """发送HTTP请求。
        
        参数：
        - method：请求方法；
        - url：URL；
        - data：DATA，POST等请求时可填写；
        """
        method = method.upper()

        paras = {}
        if method in ["GET"]:
            paras["params"] = data
        elif method in ["POST", "PUT", "DELETE"]:
            paras["data"] = json.dumps(data)
        else:
            logger.error(u"使用意料外的方法：%s" % method)
            raise Exception("use unexpected http request methud")
        
        r = requests.request(method, url, headers=self.__headers, **paras)
        self.__err_handle(r)

        return r.json()

    def search_v3(self, page=1, pageSize=1, **kwargs):
        """ 实例搜索。
        参考：https://admin.easyops.local/next/developers/providers-v2/cmdb?group=instance&api-name=post-search-v3

        参数：
        - page：页数；
        - pageSize：页大小；
        - **kwargs：其他参数，示例：
        {
            "query": {},
            "fields": ["name"],
            "page": 1,
            "page_size": 1,
            ...
        }；
        """
        api = "/v3/object/{objectId}/instance/_search"
        url = self.__url + api.format(objectId=self.modelId)

        _datas = {
            "query": {},
            "fields": ["instanceId"],
            "page": page,
            "page_size": pageSize,
        }
        _datas.update(**kwargs)

        res = self.__send_request("POST", url, data=_datas)

        return res
    
    def import_instance(self, keys, datas):
        """实例批量编辑。
        参考：https://admin.easyops.local/next/developers/providers-v2/cmdb?group=instance&api-name=import-instance

        参数：
        - keys：唯一键；
        - datas：数据集合，示例：
        {
            "keys": ["name"],
            "datas": [
                {
                    "name": "example",
                },
                ...
            ]
        }；
        """
        api = "/object/{objectId}/instance/_import"
        url = self.__url + api.format(objectId=self.modelId)

        _datas = {
            "keys": keys,
            "datas": datas
        }

        res = self.__send_request("POST", url, data=_datas)

        return res
    
    def auto_discovery(self, datas):
        """实例自动发现，按照筛选条件更新数据。
        参考：https://admin.easyops.local/next/developers/providers-v2/cmdb?group=instance&api-name=auto-discovery

        参数：
        - datas：数据集合，示例：
        [
            {
                "filter": {
                    "name": "name"
                },
                "update": {
                    "foo": "bar"
                },
                "upsert": true
            },
            ...
        ]；
        """
        api = "/object/{objectId}/instance/_import-json"
        url = self.__url + api.format(objectId=self.modelId)

        res = self.__send_request("POST", url, data=datas)

        return res

    def clear_attr_rela(self, attrNameList=[], relaNameList=[]):
        """清空所有实例的指定书属性或关系。
        
        参数：
        - attrNameList：要清空的属性名称列表；
        - relaNameList：要清空的关系名称列表；
        """
        instances = self.get_all(self.search_v3)

        keys = ["instanceId"]
        datas = []
        for instance in instances:
            data = {}
            data.update({k: None for k in attrNameList})
            data.update({k: [] for k in relaNameList})
            data["instanceId"] = instance["instanceId"]
            datas.append(data)
        
        res = self.import_instance(keys, datas)
        